//
// Copyright (c) 2009 All Right Reserved
//
// vl
//
// 2009-01-01
// Contains ...
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using JetBrains.Annotations;
namespace LargoCommon.Music
{
///
/// Melodic Analyzer.
///
[UsedImplicitly]
public sealed class MelodicAnalyzer {
#region Properties
///
/// Gets the melodic model.
///
///
/// The melodic model.
///
public MelodicModel MelodicModel { get; private set; }
///
/// Gets the rhythmic model.
///
///
/// The rhythmic model.
///
public RhythmicModel RhythmicModel { get; private set; }
#endregion
#region Public methods - Melodic Analyze
///
/// Analyze Musical Lines.
///
/// The melodic model.
/// The rhythmic model.
/// The musical block.
public void AnalyzeMusicalLines(MelodicModel melodicModel, RhythmicModel rhythmicModel, MusicalBlock givenBlock) {
Contract.Requires(givenBlock != null);
//// if (givenBlock == null) { return; }
this.MelodicModel = melodicModel;
this.RhythmicModel = rhythmicModel;
//// Cannot be run as parallel (because of direct addition of motives to entity framework collections?!?)
IList melodicItems = this.ExtractMelodicItems(givenBlock);
var melodicStreamAnalyzer = new MelodicStreamAnalyzer(melodicItems);
var itemGroups = new List();
//// Determine motives as group of items
foreach (var musicalTrack in givenBlock.Strip.Lines) {
while (true) {
var items = melodicStreamAnalyzer.GetNextMotiveItems(musicalTrack.LineIndex); //// .ToList();
if (items == null || !items.Any()) {
break;
}
var itemGroup = new MelodicItemGroup(items, musicalTrack);
itemGroups.Add(itemGroup);
}
}
//// Main algorithm to determine motivic classes and their instances
this.RhythmicModel.AppendRhythmicMotives(itemGroups);
this.MelodicModel.AppendMelodicMotives(itemGroups);
}
///
/// Extracts the melodic items.
///
/// The given block.
///
/// Returns object.
///
public IList ExtractMelodicItems(MusicalBlock givenBlock) {
List items = new List();
//// MusicalTone lastMelodicTone = null;
for (int lineIndex = 0; lineIndex < givenBlock.Header.NumberOfLines; lineIndex++) {
foreach (var bar in givenBlock.Body.Bars) {
var element = bar.Elements[lineIndex];
if (element.Line == null || !element.Status.HasContent) {
continue;
}
//// Rhythmical and melodical structure in bar
//// Rhythmical structure in bar
RhythmicStructure rstruct = element.Status.RhythmicStructure;
if (rstruct == null) {
continue;
}
//// Melodic structure in bar
MelodicStructure mstruct = null;
var isMelodic = element.Status.IsMelodic;
if (isMelodic) {
mstruct = element.Status.MelodicStructure;
}
var musicalTonesInBar = element.Tones;
MusicalToneCollection melodicTonesInBar = element.SingleMelodicTones();
var melodicItem = new MelodicItem(bar, element.Line.LineIndex, rstruct, mstruct) {
MusicalTones = musicalTonesInBar,
MelodicTones = melodicTonesInBar
};
items.Add(melodicItem);
}
}
return items;
}
#endregion
}
}